using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content;

namespace Bombardiman
{
    public class GameEngine : Microsoft.Xna.Framework.Game
    {
        private static GameEngine gameEngineObj = null;
        private GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;
        private List<Wall> walls;
        private Player player;
        private List<Enemy> enemies = new List<Enemy>();
        private List<Bomb> bombs = new List<Bomb>();
        private List<Explosion> explosions = new List<Explosion>();
        private Map map;
        private KeyboardState ks;
        private KeyboardState pks;
        private int blockSize = 100;
        private GameEngine()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        public static GameEngine getInstance()
        {
            if (gameEngineObj == null)
                gameEngineObj = new GameEngine();
            return gameEngineObj;
        }

        public ContentManager getContent()
        {
            return Content;
        }
        protected override void Initialize()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            //
            graphics.PreferredBackBufferWidth = 900;// background.Width;
            graphics.PreferredBackBufferHeight = 600;// background.Height;
            graphics.ApplyChanges();
            //
                     
            map = new Map();
            walls = map.getWallList();
            player = new Player(); 
            enemies.Add(new Enemy());

            base.Initialize();
        }
        private bool enemyCanMove(Rectangle rectangle1)
        {
            Rectangle rectangle2;

            // Do the collision between the player and the walls
            for (int i = 0; i < walls.Count; i++)
            {
                rectangle2 = new Rectangle((int)walls[i].getPosition().X,
                (int)walls[i].getPosition().Y,
                walls[i].getWidth(),
                walls[i].getHeight());

                // Determine if the two objects collided with each
                // other
                if (rectangle1.Intersects(rectangle2))
                {
                    return false;
                }
            }
            return true;
        }
        private void updateEnemyMove()
        {
            //         Random r = new Random();
            //          int nextValue = r.Next(0, 4); // Returns a random number from 0-3

            for (int i = 0; i < enemies.Count; i++)
            {
                if (enemies[i].getAnimation().getDirection() == 0)
                {
                    Rectangle rectangle1 = new Rectangle((int)enemies[i].getPosition().X - (int)enemies[i].getSpeed(),
                    (int)enemies[i].getPosition().Y,
                    enemies[i].getWidth(),
                    enemies[i].getHeight());

                    if (enemyCanMove(rectangle1))
                    {
                        enemies[i].moveLeft();
                    }
                    else
                    {
                        Random r = new Random();
                        int nextValue = r.Next(0, 4); // Returns a random number from 0-3

                        enemies[i].getAnimation().setDirection(nextValue);
                    }
                }
                if (enemies[i].getAnimation().getDirection() == 1)
                {
                    Rectangle rectangle1 = new Rectangle((int)enemies[i].getPosition().X + (int)enemies[i].getSpeed(),
                    (int)enemies[i].getPosition().Y,
                    enemies[i].getWidth(),
                    enemies[i].getHeight());

                    if (enemyCanMove(rectangle1))
                    {
                        enemies[i].moveRight();
                    }
                    else
                    {
                        Random r = new Random();
                        int nextValue = r.Next(0, 4); // Returns a random number from 0-3

                        enemies[i].getAnimation().setDirection(nextValue);
                    }
                }
                if (enemies[i].getAnimation().getDirection() == 2)
                {
                    Rectangle rectangle1 = new Rectangle((int)enemies[i].getPosition().X,
                    (int)enemies[i].getPosition().Y - (int)enemies[i].getSpeed(),
                    enemies[i].getWidth(),
                    enemies[i].getHeight());

                    if (enemyCanMove(rectangle1))
                    {
                        enemies[i].moveUp();
                    }
                    else
                    {
                        Random r = new Random();
                        int nextValue = r.Next(0, 4); // Returns a random number from 0-3

                        enemies[i].getAnimation().setDirection(nextValue);
                    }
                }
                if (enemies[i].getAnimation().getDirection() == 3)
                {
                    // Only create the rectangle once for the player
                    Rectangle rectangle1 = new Rectangle((int)enemies[i].getPosition().X,
                    (int)enemies[i].getPosition().Y + (int)enemies[i].getSpeed(),
                    enemies[i].getWidth(),
                    enemies[i].getHeight());

                    if (enemyCanMove(rectangle1))
                    {
                        enemies[i].moveDown();
                    }
                    else
                    {
                        Random r = new Random();
                        int nextValue = r.Next(0, 4); // Returns a random number from 0-3

                        enemies[i].getAnimation().setDirection(nextValue);
                    }
                }
            }
        }
        private void UpdateWalls()
        {
            // Update the walls
            for (int i = walls.Count - 1; i >= 0; i--)
            {
                if (walls[i].isActive() == false)
                {
                    walls.RemoveAt(i);
                }
            }
        }
        private void UpdateCollisionExplosionWall()
        {
            Rectangle rectangle1;
            Rectangle rectangle2;

            // Do the collision between the explosions and the walls
            for (int i = 0; i < walls.Count; i++)
            {
                rectangle1 = new Rectangle((int)walls[i].getPosition().X,
                                            (int)walls[i].getPosition().Y,
                                            walls[i].getWidth(),
                                            walls[i].getHeight());

                for (int j = 0; j < explosions.Count; j++)
                {
                    rectangle2 = new Rectangle((int)explosions[j].getPosition().X,
                                    (int)explosions[j].getPosition().Y,
                                    explosions[j].getWidth(),
                                    explosions[j].getHeight());



                    // Determine if the two objects collided with each
                    // other
                    if (rectangle1.Intersects(rectangle2))
                    {
                        if (walls[i].isDestroyable())
                            walls[i].setActive(false);
                    }
                }
            }
        }
        private void UpdateCollisionEnemies()
        {
            Rectangle rectangle1;
            Rectangle rectangle2;

            // Do the collision between the explosions and the walls
            for (int i = 0; i < enemies.Count; i++)
            {
                rectangle1 = new Rectangle((int)enemies[i].getPosition().X,
                                            (int)enemies[i].getPosition().Y,
                                            enemies[i].getWidth(),
                                            enemies[i].getHeight());

                for (int j = 0; j < explosions.Count; j++)
                {
                    rectangle2 = new Rectangle((int)explosions[j].getPosition().X,
                                    (int)explosions[j].getPosition().Y,
                                    explosions[j].getWidth(),
                                    explosions[j].getHeight());

                    // Determine if the two objects collided with each
                    // other
                    if (rectangle1.Intersects(rectangle2))
                    {
                        enemies[i].setActive(false);
                    }
                }
            }
        }
        private void addBomb()
        {
            Bomb bomb = new Bomb(player.getPosition());
            bombs.Add(bomb);
        }
        private void addExplosion(Vector2 pos)
        {
            //add 4 explosions to neighboorhood current position, and add one to position.
            Explosion explosion1 = new Explosion(pos);
            Explosion explosion2 = new Explosion(new Vector2(pos.X - blockSize, pos.Y));
            Explosion explosion3 = new Explosion(new Vector2(pos.X + blockSize, pos.Y));
            Explosion explosion4 = new Explosion(new Vector2(pos.X, pos.Y - blockSize));
            Explosion explosion5 = new Explosion(new Vector2(pos.X, pos.Y + blockSize));

            explosions.Add(explosion1);
            explosions.Add(explosion2);
            explosions.Add(explosion3);
            explosions.Add(explosion4);
            explosions.Add(explosion5);
        }
        private bool outOfBomb()
        {
            // Use the Rectangle's built-in intersect function to 
            // determine if two objects are overlapping
            Rectangle rectangle1;
            Rectangle rectangle2;

            // Only create the rectangle once for the player
            rectangle1 = new Rectangle((int)player.getPosition().X - (int)player.getSpeed(),
            (int)player.getPosition().Y,
            player.getWidth(),
            player.getHeight());

            // Do the collision between the player and the walls
            for (int i = 0; i < bombs.Count; i++)
            {
                rectangle2 = new Rectangle((int)bombs[i].getPosition().X,
                (int)bombs[i].getPosition().Y,
                bombs[i].getWidth(),
                bombs[i].getHeight());

                // Determine if the two objects collided with each
                // other
                if (rectangle1.Intersects(rectangle2))
                {
                    return false;
                }
            }
            return true;
        }
        private bool canMoveLeft()
        {
            // Use the Rectangle's built-in intersect function to 
            // determine if two objects are overlapping
            Rectangle rectangle1;
            Rectangle rectangle2;

            // Only create the rectangle once for the player
            rectangle1 = new Rectangle((int)player.getPosition().X - (int)player.getSpeed(),
            (int)player.getPosition().Y,
            player.getWidth(),
            player.getHeight());

            // Do the collision between the player and the walls
            for (int i = 0; i < walls.Count; i++)
            {
                rectangle2 = new Rectangle((int)walls[i].getPosition().X,
                (int)walls[i].getPosition().Y,
                walls[i].getWidth(),
                walls[i].getHeight());

                // Determine if the two objects collided with each
                // other
                if (rectangle1.Intersects(rectangle2))
                {
                    return false;
                }
            }
            //            return outOfBomb();
            return true;
        }
        private bool canMoveRight()
        {
            // Use the Rectangle's built-in intersect function to 
            // determine if two objects are overlapping
            Rectangle rectangle1;
            Rectangle rectangle2;

            // Only create the rectangle once for the player
            rectangle1 = new Rectangle((int)player.getPosition().X + (int)player.getSpeed(),
            (int)player.getPosition().Y,
            player.getWidth(),
            player.getHeight());

            // Do the collision between the player and the walls
            for (int i = 0; i < walls.Count; i++)
            {
                rectangle2 = new Rectangle((int)walls[i].getPosition().X,
                (int)walls[i].getPosition().Y,
                walls[i].getWidth(),
                walls[i].getHeight());

                // Determine if the two objects collided with each
                // other
                if (rectangle1.Intersects(rectangle2))
                {
                    return false;
                }
            }
            //            return outOfBomb();
            return true;
        }
        private bool canMoveUp()
        {
            // Use the Rectangle's built-in intersect function to 
            // determine if two objects are overlapping
            Rectangle rectangle1;
            Rectangle rectangle2;

            // Only create the rectangle once for the player
            rectangle1 = new Rectangle((int)player.getPosition().X,
            (int)player.getPosition().Y - (int)player.getSpeed(),
            player.getWidth(),
            player.getHeight());

            // Do the collision between the player and the walls
            for (int i = 0; i < walls.Count; i++)
            {
                rectangle2 = new Rectangle((int)walls[i].getPosition().X,
                (int)walls[i].getPosition().Y,
                walls[i].getWidth(),
                walls[i].getHeight());

                // Determine if the two objects collided with each
                // other
                if (rectangle1.Intersects(rectangle2))
                {
                    return false;
                }
            }
            //            return outOfBomb();
            return true;
        }
        private bool canMoveDown()
        {
            // Use the Rectangle's built-in intersect function to 
            // determine if two objects are overlapping
            Rectangle rectangle1;
            Rectangle rectangle2;

            // Only create the rectangle once for the player
            rectangle1 = new Rectangle((int)player.getPosition().X,
            (int)player.getPosition().Y + (int)player.getSpeed(),
            player.getWidth(),
            player.getHeight());

            // Do the collision between the player and the walls
            for (int i = 0; i < walls.Count; i++)
            {
                rectangle2 = new Rectangle((int)walls[i].getPosition().X,
                (int)walls[i].getPosition().Y,
                walls[i].getWidth(),
                walls[i].getHeight());

                // Determine if the two objects collided with each
                // other
                if (rectangle1.Intersects(rectangle2))
                {
                    return false;
                }
            }
            //            return outOfBomb();
            return true;
        }
        protected override void Update(GameTime gameTime)
        {
            player.Update(gameTime);

            UpdateCollisionExplosionWall();
            UpdateCollisionEnemies();


            for (int i = bombs.Count - 1; i >= 0; i--)
            {
                bombs[i].getAnimation().Update(gameTime);

                if (bombs[i].getAnimation().isAnimating() == false)
                {
                    addExplosion(bombs[i].getPosition());
                    bombs.RemoveAt(i);
                }
            }
            for (int i = explosions.Count - 1; i >= 0; i--)
            {
                explosions[i].Update(gameTime);

                if (explosions[i].getAnimation().isAnimating() == false)
                {
                    explosions.RemoveAt(i);
                }
            }
            for (int i = walls.Count - 1; i >= 0; i--)
            {
                walls[i].Update(gameTime);

                if (walls[i].isActive() == false)
                {
                    walls.RemoveAt(i);
                }
            }
            for (int i = enemies.Count - 1; i >= 0; i--)
            {
                enemies[i].Update(gameTime);

                if (enemies[i].isActive() == false)
                {
                    enemies.RemoveAt(i);
                }
            }

            ks = Keyboard.GetState();

            if (ks.GetPressedKeys().Length > 0 &&
                (ks.IsKeyDown(Keys.Left) || ks.IsKeyDown(Keys.Right) || ks.IsKeyDown(Keys.Up) || ks.IsKeyDown(Keys.Down)))
            {
                player.setMotion(new Walking());
                player.getAnimation().setAnimating(true);
            }
            else
            {
                player.getAnimation().setAnimating(false);
                player.setMotion(new Standing());
            }
            if (ks.IsKeyDown(Keys.Q) || ks.IsKeyDown(Keys.Escape))
                Exit();

            if (ks.IsKeyDown(Keys.Left))
            {
                if (canMoveLeft())
                    player.moveLeft();

            }
            if (ks.IsKeyDown(Keys.Right))
            {
                if (canMoveRight())
                    player.moveRight();

            }
            if (ks.IsKeyDown(Keys.Up))
            {
                if (canMoveUp())
                    player.moveUp();
            }
            if (ks.IsKeyDown(Keys.Down))
            {
                if (canMoveDown())
                    player.moveDown();
            }


            updateEnemyMove();


            if (pks.IsKeyDown(Keys.Space) && ks.IsKeyUp(Keys.Space))
            {
                if (bombs.Count < 1)
                {
                    addBomb();
                }
            }

            pks = ks;

            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.DimGray);
            spriteBatch.Begin();
            // Start drawing
            for (int i = 0; i < walls.Count; i++)
            {
                walls[i].Draw(spriteBatch);
            }

            for (int i = 0; i < bombs.Count; i++)
            {
                bombs[i].Draw(spriteBatch);
            }

            for (int i = 0; i < explosions.Count; i++)
            {
                explosions[i].Draw(spriteBatch);
            }

            for (int i = 0; i < enemies.Count; i++)
            {
                enemies[i].Draw(spriteBatch);
            }

            player.Draw(spriteBatch);

            // Stop drawing
            spriteBatch.End();

            base.Draw(gameTime);
        }
        
    }
}
